#include "RegistroComprimidoDatos.h"
#include "../common/SerialInator.h"


RegistroComprimidoDatos::RegistroComprimidoDatos() :
	_cantCoincidencias(-1), _claveComprimida("")
{
}


RegistroComprimidoDatos::RegistroComprimidoDatos(std::string clave, std::string claveAnterior,
			unsigned int posRel, unsigned short int res)
	: RegistroDatos(clave, posRel, res)
{
	unsigned short int cantCaracteresIguales = 0;
	this->_claveComprimida = comprimirTermino(clave, claveAnterior, cantCaracteresIguales);
	this->_cantCoincidencias = cantCaracteresIguales;
}


RegistroComprimidoDatos::RegistroComprimidoDatos(RegistroDatos& r){
	this->clavePrimaria = r.getClave();
	this->setPosEnDiccionario( r.getPosEnDiccionario() );
	this->setReservado( r.getReservado() );

	// No estan los datos necesarios para la compresion de la clave
	this->_cantCoincidencias = -1;
	this->_claveComprimida = "";
}


RegistroComprimidoDatos::~RegistroComprimidoDatos() {
	this->_cantCoincidencias = -1;
	this->_claveComprimida = "";
}


std::string RegistroComprimidoDatos::getClave(std::string claveAnterior){
	// La clave ya fue descomprimida
	if (this->clavePrimaria != ""){
		return this->clavePrimaria;
	}

	// Se descomprime la clave
	this->clavePrimaria = descomprimirTermino(this->_claveComprimida, claveAnterior, this->_cantCoincidencias);

	return this->clavePrimaria;
}


// Setea la clave y la clave comprimida
void RegistroComprimidoDatos::setClaveComprimida(std::string clave, std::string claveAnterior){
	this->clavePrimaria = clave;

	unsigned short int cantCaracteresIguales = 0;
	this->_claveComprimida = comprimirTermino(clave, claveAnterior, cantCaracteresIguales);
	this->_cantCoincidencias = cantCaracteresIguales;
}


// Obtiene la clave dada las diferencias
std::string RegistroComprimidoDatos::descomprimirTermino(std::string claveComprimida, std::string claveAnterior, unsigned short int cantCoincidencias) const{
	return claveAnterior.substr(0, cantCoincidencias) + claveComprimida;
}


// Obtiene la diferencia entre las claves
std::string RegistroComprimidoDatos::comprimirTermino(std::string clave, std::string claveAnterior, unsigned short int &cantCoincidencias) const{

	// Si la clave anterior esta vacia no me gasto en calcular nada
	if (claveAnterior == ""){
		cantCoincidencias = 0;
		return clave;
	}

	unsigned short int i = 0;
	while (clave[i] == claveAnterior[i] && i < clave.length() && i < claveAnterior.length()){
		// Cuenta con cuantas letras en común comienzan las claves
		++i;
	}

	// Se devuelve la cantidad de letras que son iguales entre las claves
	cantCoincidencias = i;

	// Se devuelve la clave sin las letras que comparte con la clave anterior
	return clave.substr(i);
}


int RegistroComprimidoDatos::serializar(char* arrBytes){
	SerialInator s;
	s.reset();

	char pipe = '|';	// Separador para debug
	s.serializar(arrBytes, pipe);
	s.serializar(arrBytes, this->_cantCoincidencias);
	s.serializar(arrBytes, this->_claveComprimida);
	s.serializar(arrBytes, this->getPosEnDiccionario());
	s.serializar(arrBytes, this->getReservado());

	return s.getBufferSize();
}


int RegistroComprimidoDatos::getSize() const{
	int tam = sizeof(char);	// El separador de registros
	
	// La clave comprimida
	tam += sizeof(this->_cantCoincidencias);
	tam += SerialInator::getSizeOf(this->_claveComprimida);

	// Los datos que se guardan en el registro
	tam += sizeof(this->getPosEnDiccionario()) + sizeof(this->getReservado());

	return tam;
}


int RegistroComprimidoDatos::desSerializar(char* arrBytes){
	SerialInator s;
	s.reset();

	char pipe = '|';
	unsigned int pos = 0;
	unsigned short int reservado = 0;

	s.desSerializar(arrBytes, pipe);
	s.desSerializar(arrBytes, this->_cantCoincidencias);
	s.desSerializar(arrBytes, this->_claveComprimida);
	s.desSerializar(arrBytes, pos);
	s.desSerializar(arrBytes, reservado);

	this->setPosEnDiccionario(pos);
	this->setReservado(reservado);

	return s.getBufferSize();
}


void RegistroComprimidoDatos::ImprimirEn(std::ostream& out) const{
	out << "|(" << this->_cantCoincidencias << ")"
			<< "(" << this->_claveComprimida.length() << ")"
			<< this->_claveComprimida << ","
			<< this->getPosEnDiccionario() << ","
			<< this->getReservado();
}

